﻿using System;
using System.Collections.Generic;
using System.IO;

namespace Safebrowsing
{
    public class Chunk
    {
        /// <summary>
        /// Creates Chunk from it's data.
        /// Look here for info on data format: http://code.google.com/apis/safebrowsing/developers_guide_v2.html#ShavarListFormat
        /// </summary>
        /// <param name="number"></param>
        /// <param name="type"></param>
        /// <param name="hashLength"></param>
        /// <param name="data"></param>
        public Chunk(int number, ChunkType type, int hashLength, byte[] data)
        {
            Number = number;
            Type = type;
            HashLength = hashLength;
            ChunkDataList = new List<ChunkData>();

            if (data.Length == 0) return;

            using (Stream stream = new MemoryStream(data) { Position = 0 })
            {
                while (stream.Position < data.Length - 1)
                {
                    byte[] head = Utils.Read(stream, 4);
                    int count = stream.ReadByte();
                    int hostKey = Utils.ToInt(head, 0);
                    var chunkData = new ChunkData(hostKey);

                    if (type == ChunkType.Add)
                    {
                        // For ADD-DATA -- just reading list of prefixes
                        if (count > 0)
                        {
                            for (int i = 0; i < count; i++)
                            {
                                byte[] prefix = Utils.Read(stream, HashLength);
                                chunkData.AddPrefix(prefix);
                            }
                        }
                    }
                    else
                    {
                        // For SUB-DATA -- reading ADDCHUNKNUM - PREFIX pairs
                        if (count == 0)
                        {
                            int addChunkNumber = Utils.ToInt(Utils.Read(stream, 4), 0);
                            chunkData.AddSubData(addChunkNumber, null);
                        }
                        else
                        {
                            for (int i = 0; i < count; i++)
                            {
                                int addChunkNumber = Utils.ToInt(Utils.Read(stream, 4), 0);
                                byte[] prefix = Utils.Read(stream, HashLength);
                                chunkData.AddSubData(addChunkNumber, prefix);
                            }
                        }
                    }

                    ChunkDataList.Add(chunkData);
                }
            }
        }

        /// <summary>
        /// Chunk's number
        /// </summary>
        public int Number { get; private set; }

        /// <summary>
        /// Chunk's type. Chunk may be of two types: add or sub.
        /// Add chunk contains new entries for the list.
        /// Sub chunk contains entries that need to be removed from the client's list.
        /// </summary>
        public ChunkType Type { get; private set; }

        /// <summary>
        /// Decimal length of each hash prefix in bytes
        /// </summary>
        public int HashLength { get; private set; }

        /// <summary>
        /// List of chunkdata
        /// </summary>
        public List<ChunkData> ChunkDataList { get; private set; }

        public override string ToString()
        {
            return string.Format("{0} number: {1}, hash length: {2}, host keys count: {3}",
                                 Enum.GetName(typeof (ChunkType), Type), Number, HashLength, ChunkDataList.Count);
        }
    }
}
